package com.sb.registration.component.service.impl;

import java.io.IOException;
import java.util.List;

import javax.jws.WebService;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.sb.registration.component.exceptions.DatastoreSystemException;
import com.sb.registration.component.exceptions.UserAlreadyExistsException;
import com.sb.registration.component.exceptions.UserDoesNotExistException;
import com.sb.registration.component.model.ErrorDetails;
import com.sb.registration.component.model.UserRegistrationServiceResult;
import com.sb.registration.component.model.UserWrapper;
import com.sb.registration.component.model.mapper.UserDataMapper;
import com.sb.registration.component.service.UserRegistrationManager;
import com.sb.registration.component.service.UserRegistrationService;
import com.sb.registration.component.service.UserValidator;
import com.sb.registration.component.service.ds.UsersDataSource;
import com.sb.registration.data.jaxb.gen.Users.User;

/**
 * {@inheritDoc}
 * 
 * 
 * @author gautam.amitkumar@gmail.com
 *
 */
@Service("userRegistrationManager")
@WebService(serviceName = "UserRegistrationService", endpointInterface = "com.sb.registration.component.service.UserRegistrationService")
public class UserRegistrationManagerImpl implements UserRegistrationService, UserRegistrationManager {

	private static Log logger_ = LogFactory.getLog(UserRegistrationManagerImpl.class);
	
	

	/**
	 * user data mapper for converting userwrapper to xml data user type
	 */
	@Autowired
	private UserDataMapper userDataMapper;
	
	/**
	 * data repository for users
	 */
	@Autowired
	private UsersDataSource usersDataSource;
	
	@Autowired
	private UserValidator userValidator;

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult addUser(UserWrapper userData) {
		
		//LOGIC TO VALIDATE USERS DATA - EMAIL, CHANNEL, IP
		
		logger_.debug("Request for registration of new user - " + userData.toString());

		UserRegistrationServiceResult result = getResultObject();
		
		try {
			
			String validationResult = userValidator.validateUser(userData);
			
			if(StringUtils.isNotBlank(validationResult)){
				result.setStatus(UserRegistrationServiceResult.FAILURE);
				result.setErrorDetails(getErrorDetailsObject(104, UserRegistrationServiceResult.errorMap.get(104) + validationResult, validationResult));
				return result;
			}
			
			usersDataSource.addUser(userDataMapper.getXMLUserObj(userData));
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
			
		} catch (UserAlreadyExistsException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(103, UserRegistrationServiceResult.errorMap.get(103), e.getMessage()));
		} catch (DatastoreSystemException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
		}
		
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult updateUser(UserWrapper userData) {
		
		logger_.debug("Request for registration user update - " + userData.toString());
		
		UserRegistrationServiceResult result = getResultObject();
		
		try {
			
			usersDataSource.updateUser(userDataMapper.getXMLUserObj(userData));
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
			
		} catch (DatastoreSystemException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
		} catch (UserDoesNotExistException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(101, UserRegistrationServiceResult.errorMap.get(101), e.getMessage()));
		}
		
		return result;
		
	}

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult deleteUser(UserWrapper userData) {
		
		logger_.debug("Request for deletion of user - " + userData.toString());
		
		UserRegistrationServiceResult result = getResultObject();
		
		try {
			
			usersDataSource.deleteUser(userDataMapper.getXMLUserObj(userData));
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
			
		} catch (DatastoreSystemException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
		} catch (UserDoesNotExistException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(101, UserRegistrationServiceResult.errorMap.get(101), e.getMessage()));
		}
		
		return result;
		
	}

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult deleteUser(String emailId) {
		
		logger_.debug("Request for deletion of user - " + emailId);
		
		UserRegistrationServiceResult result = getResultObject();
		
		try {
			
			usersDataSource.deleteUser(emailId);
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
			
		} catch (DatastoreSystemException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
		} catch (UserDoesNotExistException e) {
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(101, UserRegistrationServiceResult.errorMap.get(101), e.getMessage()));
		}
		
		return result;
		
	}

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult fetchAllUsers() {
		
		logger_.debug("Request for fetching all users");
		
		UserRegistrationServiceResult result = getResultObject();
		
		try{
		
			List<User> userList = usersDataSource.getAllUsers();
			
			result.setUserList(userDataMapper.mapUserList(userList));
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
		
		}catch(Exception e){
			
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
			
		}
				
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult getUser(String emailId) {
		
		logger_.debug("Request for fetching user with emailId - " + emailId);
		
		UserRegistrationServiceResult result = getResultObject();
		
		try{
		
			result.setUserData(userDataMapper.getUserData(usersDataSource.getUser(emailId)));
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
		
		}catch(Exception e){
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
		}
		
		return result;
	}

	/**
	 * {@inheritDoc}
	 */
	public UserRegistrationServiceResult clearAll() {
		
		logger_.debug("Request for deleting all existing users from the system.");
		
		UserRegistrationServiceResult result = getResultObject();
		
		try {
			
			usersDataSource.clearAll();
			
			result.setStatus(UserRegistrationServiceResult.SUCCESS);
			
		} catch (IOException e) {
			
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
			
		} catch (DatastoreSystemException e) {
			
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
			
		} catch(Exception e){
			
			result.setStatus(UserRegistrationServiceResult.FAILURE);
			result.setErrorDetails(getErrorDetailsObject(102, UserRegistrationServiceResult.errorMap.get(102), e.getMessage()));
		}
		
		return result;
		
	}
	
	/**
	 * Method to create result object. 
	 * This can be implemented using factory (creational pattern) or using spring prototype bean in future.
	 *
	 * @return UserRegistrationServiceResult
	 */
	private UserRegistrationServiceResult getResultObject(){
		return new UserRegistrationServiceResult();
	}
	
	/**
	 * Method to create ErrorDetails object. 
	 * This can be implemented using factory (creational pattern) or using spring prototype bean in future.
	 *
	 * @return ErrorDetails
	 */
	private ErrorDetails getErrorDetailsObject(int errorCode, String errorMessage, String exceptionMessage){
		
		ErrorDetails errorDetails = new ErrorDetails();
		errorDetails.setErrorCode(errorCode);
		errorDetails.setErrorMessage(errorMessage);
		errorDetails.setExceptionMessage(exceptionMessage);
		
		return errorDetails;
	}
	
}
